package org.jradweb.tools.generator.xml;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.maven.plugin.logging.Log;
import org.jradweb.tools.generator.freemarker.Value;
import org.jradweb.tools.generator.utils.ConfigExistsException;
import org.jradweb.tools.generator.utils.LogImpl;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

public class SpringServletOperator extends XmlOperator {

	public SpringServletOperator(File rootPath, String groupId,
			String artifactId, Log log) throws IOException,
			ParserConfigurationException, SAXException {
		super(rootPath, groupId, artifactId, log);
		File xmlFile = new File(rootPath.getAbsoluteFile()
				+ "/src/main/webapp/WEB-INF/spring-servlet.xml");
		if (!xmlFile.exists()) {
			String msg = "Spring config file not exits, please create it manually: "
					+ xmlFile.getAbsolutePath();
			this.getLog().error(msg);
			throw new IOException(msg);

		}
		this.setXmlFile(xmlFile);

		this.document = this.initDocument(this.getXmlFile());
	}

	public void addHandlerMapping(String controllerName, String pathName)
			throws Exception {
		Value controller = new Value(controllerName);
		Value path = new Value(pathName);

		Element beans = document.getDocumentElement();

		Node handlerMappingBean = this.getHandlerMappingBean();
		if (handlerMappingBean == null) {
			// if use this bean, need not handlerMapping, since 0.0.2

			String msg = "No bean \"handlerMapping\" found in file: "
					+ this.getXmlFile();
			this.getLog().error(msg);
			throw new IOException(msg);
		}

		try {
			this.addMapping(handlerMappingBean, controller.getLowerCaseFirst(),
					path.getLowerCaseFirst());

		} catch (ConfigExistsException e) {
			this.getLog().warn(e.getMessage());
			return;
		}
		/*------------------------------------------------*/
		/* Save Document */
		/*------------------------------------------------*/
		this.saveDocument(XML_TYPE_SPRING);
		this.getLog().info(
				"Spring spring-servlet added mapping for controller \""
						+ controller + "\".");
	}

	private boolean addMapping(Node handlerMap, String name, String path)
			throws Exception {

		Node mappings = this.getChildNode(handlerMap, "property", "name",
				"mappings");
		if (mappings == null) {
			Node urlMapResolver = this.getChildNode(handlerMap, "property",
					"name", "urlMapResolver");
			if (urlMapResolver != null) {
				this.getLog().info(
						"Using urlMapResolver:'" + urlMapResolver.toString()
								+ "', skip add controller mapping");
				return false;
			}

			String message = "No \"property\" node in handlerMapping bean";
			throw new Exception(message);
		}

		Node props = this.getChildNode(mappings, "props", null, null);
		if (props == null) {
			String message = "No \"props\" node in \"props\" node of handlerMapping bean";
			throw new Exception(message);
		}

		Node oldNode = this.getChildNode(props, "prop", "key", path + "/*");
		if (oldNode != null) {
			String message = "Mapping for path \"" + path
					+ "/*\" already exists!";
			throw new ConfigExistsException(message);
		}
		// create prop node
		Element newProp = this.document.createElement("prop");
		newProp.setAttribute("key", path + "/*");
		Text text = this.document.createTextNode(name + "Controller");
		newProp.appendChild(text);

		props.appendChild(newProp);

		return true;
	}

	private Node getChildNode(Node parent, String nodeName,
			String attributeName, String attributeValue) {

		NodeList nodeList = parent.getChildNodes();
		for (int i = 0; i < nodeList.getLength(); i++) {
			Node n = nodeList.item(i);
			if (n.getNodeName().equals(nodeName)) {
				if (attributeName == null)
					return n;

				NamedNodeMap nnm = n.getAttributes();
				Node name = nnm.getNamedItem(attributeName);
				if (name != null && attributeValue == null) {
					return n;
				} else if (name != null
						&& attributeValue.equals(name.getNodeValue())) {
					return n;
				}
			}
		}

		return null;
	}

	private Node getHandlerMappingBean() {
		Element beans = document.getDocumentElement();

		NodeList beanList = beans.getChildNodes();
		for (int i = 0; i < beanList.getLength(); i++) {
			Node bean = beanList.item(i);

			if (bean.getNodeName().equals("bean")) {

				NamedNodeMap nnm = bean.getAttributes();
				for (int j = 0; j < nnm.getLength(); j++) {
					Node node = nnm.item(j);
					if (node.getNodeName().equals("id")
							&& node.getNodeValue().equals("handlerMapping")) {
						return bean;
					}

				}
			}
		}
		return null;
	}

	// org.jradweb.core.web.DefaultUrlMapResolver

	public static void main(String[] args) {
		SpringServletOperator opr;
		String name = "customer";
		try {
			File projectRootPath = new File("D:/workspace2/jradtest");
			opr = new SpringServletOperator(projectRootPath, "org.jradweb",
					"jradtest", new LogImpl(SpringServletOperator.class));
			opr.addHandlerMapping(name, name);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}
